/*
*   0‌：表示WebSocket对象已创建，但连接尚未打开。
*   1‌：表示连接已打开，可以进行通信。
    2‌：表示连接正在关闭。
    3‌：表示连接已关闭或无法打开‌

* */
enum EMessageMode {
    heart = 'heart',
    msg = 'message'
}
interface IMessage {
    mode: EMessageMode
    message: {
        state: boolean
        data: string
    }
}
class Socket {
    url: string
    ws: null | WebSocket = null
    timer: undefined | number = undefined
    heartBeatTimer: undefined | number | NodeJS.Timeout = undefined
    connectTimer: undefined | number | NodeJS.Timeout = undefined
    webSocketState: boolean = false
    constructor(url: string) {
        this.url = url
        this.connectWebSocket()
    }
    // 连接websocket
    connectWebSocket() {
        this.ws = new WebSocket(this.url);
        (this.ws as WebSocket).addEventListener('open', () => {
            if (this.connectTimer) {
                clearInterval(this.connectTimer as number)
                this.connectTimer = undefined
            }
            this.webSocketState = true
            this.startHeartBeat()
        });
        (this.ws as WebSocket).addEventListener('message', (data: MessageEvent) => {
            const { mode, message } = JSON.parse(data.data as string) as IMessage
            switch (mode) {
                case EMessageMode.msg:
                    this.webSocketState = message.state
                    break
                case EMessageMode.heart:
                    this.webSocketState = message.state
                    break
            }
        });
        (this.ws as WebSocket).addEventListener('error', () => {
            if (!this.connectTimer) {
                this.connectTimer = setInterval(() => {
                    (!this.ws || (this.ws as WebSocket).readyState !== 1) && this.connectWebSocket()
                }, 10 * 1000) as NodeJS.Timeout
            }
        })
    }
    // 心跳检测
    startHeartBeat() {
        this.heartBeatTimer = setInterval(() => {
            if(this.webSocketState && (this.ws as WebSocket).readyState === 1) {
                if(this.timer) { clearInterval(this.timer); this.timer = undefined }
                (this.ws as WebSocket).send(JSON.stringify({ mode: 'heart', message: '心跳检测' }))
            } else {
                this.webSocketState = false
                !this.timer && this.reconnect()
            }
        }, 5 * 1000) as NodeJS.Timeout
    }
    // 重连websocket
    reconnect() {
        this.webSocketState = true
        if (this.heartBeatTimer) {
            clearInterval(this.heartBeatTimer as number)
            this.heartBeatTimer = undefined
        }
        this.connectWebSocket()
    }
}

export default Socket